package com.jdd.modules.sdk.utils;

import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.Locale;

/**
 * @author ：jdd孙庆伟
 * @date ：Created in 2021/10/18 10:50
 * @description：
 * @modified By：`
 * @version: 1.0
 */
@Slf4j
public class XiaoMingLedUtils {

    /**
     * 头信息
     */
    private static final String head = "AA55";
    /**
     * 流水号
     */
    private static final String serial = "00";
    /**
     * 业务类型
     */
    private static final String type = "80";
    /**
     * 临时播放文字命令
     */
    private static final String pushPlayOrder = "DA";
    /**
     * led显示命令
     */
    private static final String LedViewOrder = "D5";
    /**
     * 结尾符
     */
    private static final String stopCode = "AF";
    /**
     * 显示类型 临时显示信息
     */
    private static final String viewType = "52";
    /**
     * 显示类型 0x25：固定显示 “静态显示”
     */
    private static final String viewType25 = "25";
    /**
     * 显示类型 广告词“是在空闲显示下的内容”
     */
    private static final String viewType51 = "51";


    /**
     * LED语音播放指令
     *
     * @param str //播放语音的内容
     * @return
     * @throws Exception
     */
    public static byte[] ledPlayVoice(String str) throws Exception {
        log.info("LED语音播放内容：" + str);
        StringBuilder buffer = new StringBuilder();
        String aa = head + serial;
        String bb = type + pushPlayOrder;

        //根据，拆解播报类容
        String dataStr = "";
        String[] split = str.split(",");
        for (String spl : split) {
            Integer numb = nType.getTypeCode(spl).getValue();
            String numbStr = numToHex16(numb);
            dataStr += numbStr;
        }
        //获取字节长度
        int length = dataStr.length() / 2;
        //高位字节
        int mainVersion = (length & 0xFF00) >> 8;
        //低位
        int minorVersion = length & 0xFF;
        String tall = numToHex16(mainVersion);
        String low = numToHex16(minorVersion);

        buffer.append(aa);
        buffer.append(bb);
        buffer.append(tall);
        buffer.append(low);

        log.info("序号指令：" + dataStr);
        buffer.append(dataStr);
        log.info(bb + tall + low + dataStr);
        byte[] bytes1 = hexToByteArray(bb + tall + low + dataStr);
        int crc = CRC16(bytes1, bytes1.length);
        String crcStr = Integer.toHexString(crc).toUpperCase(Locale.ROOT);
        if (crcStr.length() >= 8) {
            buffer.append(crcStr.substring(crcStr.length() - 4));
        } else {
            buffer.append(crcStr);
        }
        buffer.append(stopCode);
        log.info("LED语音播放发送相机指令：" + buffer);
        return hexToByteArray(buffer.toString());
    }


    /**
     * LED显示
     *
     * @param
     * @param line
     * @return byte[]
     * @author jdd孙庆伟
     * @date 2021/10/19 09:24:13
     * @version 1.0
     */
    public static byte[] ledTemporaryDisplay(String str, String line)throws Exception {
        log.info("LED显示内容：" + str);
        if (str == null || str == "") {
            return null;
        }
        StringBuilder buffer = new StringBuilder();

        byte[] bytes  = str.getBytes("GB2312");
        String formatted = bytes2HexString(bytes);
        String see = LedViewOrder + formatted;
        //获取字节长度
        int length = see.length() / 2 + 1;
        //高位字节
        int mainVersion = (length & 0xFF00) >> 8;
        //低位
        int minorVersion = length & 0xFF;
        String tall = numToHex16(mainVersion);
        String low = numToHex16(minorVersion);
        //包头
        buffer.append(head);
        //流水号
        buffer.append(serial);
        //业务类型
        buffer.append(type);
        //命令类型
        buffer.append(LedViewOrder);
        //指定长度的高位
        buffer.append(tall);
        //指定长度的低位
        buffer.append(low);
        //行数
        buffer.append(line);
        //显示类型
        buffer.append(viewType);
        //数据内容
        buffer.append(formatted);
        //除去头尾信息用CRC-16/MODBUS算法得到校验字符串
        String asda = type + LedViewOrder + tall + low + line + viewType + formatted;
        log.info("sssssss---" + asda);
        byte[] bytes1 = hexToByteArray(type + LedViewOrder + tall + low + line + viewType + formatted);
        int crc = CRC16(bytes1, bytes1.length);
        String crcStr = Integer.toHexString(crc).toUpperCase(Locale.ROOT);
        if (crcStr.length() > 4) {
            buffer.append(crcStr.substring(crcStr.length() - 4));
        } else {
            buffer.append(crcStr);
        }
        buffer.append(stopCode);
        log.info("LED显示发送相机指令：" + buffer);
        return hexToByteArray(buffer.toString());
    }

    static short CRC16(byte[] ptr, int len) {
        short i;
        short index = 0;
        short crc = 0;
        while (len-- != 0) {
            for (i = 0x80; i != 0; i /= 2) {
                if ((crc & 0x8000) != 0) {
                    crc *= 2;
                    crc ^= 0x8005;
                } else {
                    crc *= 2;
                }

                if ((ptr[index] & i) != 0) {
                    crc ^= 0x8005;
                }
            }
            index++;
        }
        return crc;
    }

    /**
     * int 转16进制字符串
     *
     * @param b
     * @return
     */
    public static String numToHex16(int b) {
        return String.format("%02x", b).toUpperCase();
    }

    /**
     * hex字符串转byte数组
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte数组结果
     */
    public static byte[] hexToByteArray(String inHex) {
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1) {
            //奇数
            hexlen++;
            result = new byte[(hexlen / 2)];
            inHex = "0" + inHex;
        } else {
            //偶数
            result = new byte[(hexlen / 2)];
        }
        int j = 0;
        for (int i = 0; i < hexlen; i += 2) {
            result[j] = hexToByte(inHex.substring(i, i + 2));
            j++;
        }
        return result;
    }

    /**
     * byte数组转16进制字节字符串
     *
     * @param data
     * @return
     */
    public static String bytes2HexString(byte[] data) {
        if (data == null) {
            throw new NullPointerException();
        }

        StringBuilder buffer = new StringBuilder();
        for (byte b : data) {
            String hex = Integer.toHexString(b & 0xff);
            if (hex.length() == 1) {
                buffer.append('0');
            }
            buffer.append(hex);
        }
        return buffer.toString().toUpperCase();
    }

    /**
     * Hex字符串转byte
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte
     */
    public static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }


    public enum nType {
        HXGL("欢迎光临", 1),
        YLSF("一路顺风", 2),
        JZRC("禁止入场", 4),
        JZCC("禁止出场", 5),
        YEBZ("余额不足", 8),
        KYGQ("卡已过期", 16),
        QJF("请缴费", 17),
        SFYZC("收费月租车", 23),
        QYQ("请延期", 25),
        QLXGLY("请联系管理员", 26),
        CWYM("车位已满", 30),
        ZZRGQR("正在人工确认", 31),
        QSH("请稍候", 33),
        SY("剩余", 34),
        JE("金额", 35),
        QDJZSFCJF("请到集中收费处缴费", 36),
        BCSF("本次收费", 38),
        DIAN("点", 39),
        QINGCHONGZHI("请充值", 127),
        HEIMINGDAN("黑名单车牌", 130),
        FEITONGXINGSHIDAN("非通行时段", 133),
        TINGCHE("停车", 137),
        CHEWEIYIZHANYONG("车位已占用", 138),
        YOUXIAOQI("有效期剩余", 139),
        LINGSHI("没有找到入场车牌", 142),
        QINGRUCHANG("请入场", 145),
        QINGSAOMARUCHANG("请扫码入场", 146),
        QINGSAOMACHUCHANG("请扫码出场", 147),

        LSC("临时车", 18),
        CZC("充值车", 20),
        YZC("月租车", 19),
        MFC("免费车", 22),

        SHI("十", 40),
        BAI("百", 41),
        QIAN("千", 42),
        YUAN("元", 43),

        XIAOSHI("小时", 44),
        MIAO("秒", 45),
        FEN("分", 46),
        RR("日", 47),
        YUE("月", 48),
        TIAN("天", 49),
        NIAN("年", 50),

        A("A", 51),
        B("B", 52),
        C("C", 53),
        D("D", 54),
        E("E", 55),
        F("F", 56),
        G("G", 57),
        H("H", 58),
        I("I", 59),
        J("J", 60),
        K("K", 61),
        L("L", 62),
        M("M", 63),
        N("N", 64),
        O("O", 65),
        P("P", 66),
        Q("Q", 67),
        R("R", 68),
        S("S", 69),
        T("T", 70),
        U("U", 71),
        V("V", 72),
        W("W", 73),
        X("X", 74),
        Y("Y", 75),
        Z("Z", 76),

        LING("0", 77),
        YI("1", 78),
        ER("2", 79),
        SAN("3", 80),
        SI("4", 81),
        WU("5", 82),
        LIU("6", 83),
        QI("7", 84),
        BA("8", 85),
        JIU("9", 86),

        BEIJING("京", 87),
        TIANJING("津", 88),
        HEBEI("冀", 89),
        SHANXI("晋", 90),
        MENGGU("蒙", 91),
        LIAONING("辽", 92),
        JILIN("吉", 93),
        HEILONGJIANG("黑", 94),
        SHANGHAI("沪", 95),
        SUZHOU("苏", 96),
        ZHEJIANG("浙", 97),
        ANHUI("皖", 98),
        FUJIAN("闽", 99),
        JIANGXI("赣", 100),
        SHANDONG("鲁", 101),
        HENAN("豫", 102),
        HUBEI("鄂", 103),
        HUNAN("湘", 104),
        GUANGDONG("粤", 105),
        GUANGXI("桂", 106),
        HAINAN("琼", 107),
        CHONGQING("渝", 108),
        SICHUAN("川", 109),
        GUIZHOU("贵", 110),
        YUNNAN("云", 111),
        ZANGZU("藏", 112),
        SHANANXI("陕", 113),
        GANSU("甘", 114),
        QINGHAI("青", 115),
        NINGXIA("宁", 116),
        XINJIANG("新", 117),
        XIANGGANG("港", 118),
        AOMEN("澳", 119),
        TAIWAN("台", 120),
        JINGCHE("警", 121),
        DASHIGUAN("使", 122),
        WUJING("武警", 123),
        LINGQIU("领", 124),
        XUEYUAN("学", 125),
        JIAO("角", 126);

        private final String key;
        private final Integer value;

        private nType(String key, Integer value) {
            this.key = key;
            this.value = value;
        }

        public String getKey() {
            return key;
        }

        public Integer getValue() {
            return value;
        }

        public static nType getTypeCode(String key) {
            //stream使用findAny取得是第一个值
            //parallelStream使用findAny是随机
            return Arrays.asList(nType.values()).stream()
                    .filter(alarmGrade -> alarmGrade.getKey().equals(key))
                    .findAny().orElse(nType.HXGL);
        }
    }

}
